package com.xbongbong.saas.help;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.i18n.util.I18nMessageUtil;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.PaasAppEntity;
import com.xbongbong.paas.domain.entity.PaasFormDataEntity;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.domain.entity.ext.PaasFormEntityExt;
import com.xbongbong.paas.elasticsearch.pojo.XbbAggregatedPage;
import com.xbongbong.paas.elasticsearch.util.EsHelper;
import com.xbongbong.paas.elasticsearch.util.EsUtil;
import com.xbongbong.paas.elasticsearch.util.XbbElasticsearchRestTemplate;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.enums.FlowStatusEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.enums.PaymentSheetTypeEnum;
import com.xbongbong.paas.enums.PlatFormEnum;
import com.xbongbong.paas.help.CommonHelp;
import com.xbongbong.paas.help.subform.TransferSubFormHelper;
import com.xbongbong.paas.log.MongoLogHelp;
import com.xbongbong.paas.log.constant.LogMemoConstant;
import com.xbongbong.paas.model.PaasAppModel;
import com.xbongbong.paas.model.PaasFormModel;
import com.xbongbong.paas.pojo.MultiUnitPricePoJo;
import com.xbongbong.paas.pojo.dto.FormDataAddDTO;
import com.xbongbong.paas.pojo.dto.SaasFormSaveDTO;
import com.xbongbong.paas.pojo.vo.FormDataAddVO;
import com.xbongbong.paas.service.WorkflowOperatorDataService;
import com.xbongbong.paas.service.workflow.trigger.WorkflowFormDataOperationService;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.Arith;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.CloneUtil;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.paas.toolbox.wrap.UserVO;
import com.xbongbong.paas.util.ExplainUtil;
import com.xbongbong.pro.constant.BusinessConstant;
import com.xbongbong.pro.constant.ElasticConstant;
import com.xbongbong.pro.constant.I18nStringConstant;
import com.xbongbong.pro.contractperformance.pojo.ContractPerformanceLogPojo;
import com.xbongbong.pro.domain.entity.UpdateDataEntity;
import com.xbongbong.pro.enums.DistributorMarkEnum;
import com.xbongbong.pro.enums.ErrorCodeEnum;
import com.xbongbong.pro.enums.RefundStatusEnum;
import com.xbongbong.pro.enums.SaasMarkEnum;
import com.xbongbong.pro.enums.errorcodes.ProductErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.BusinessTypeErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.enums.workflow.TriggerEventTypeEnum;
import com.xbongbong.pro.formdata.pojo.SaasNeedRedundantAttrPojo;
import com.xbongbong.pro.listbatch.pojo.dto.CancelDTO;
import com.xbongbong.pro.log.pojo.DetailLogComplexPojo;
import com.xbongbong.pro.refund.pojo.vo.RefundRedContractVO;
import com.xbongbong.pro.user.pojo.ReturnUserAndDepartmentPojo;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.ParameterConstant;
import com.xbongbong.saas.constant.ProductConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.ContractPerformanceEntity;
import com.xbongbong.saas.domain.entity.ContractProductEntity;
import com.xbongbong.saas.domain.entity.ContractUserEntity;
import com.xbongbong.saas.domain.entity.InstockProductEntity;
import com.xbongbong.saas.domain.entity.OutstockProductEntity;
import com.xbongbong.saas.domain.entity.ProductSerialBalanceEntity;
import com.xbongbong.saas.domain.entity.ProductSerialFlowEntity;
import com.xbongbong.saas.domain.entity.RefundInvoiceEntity;
import com.xbongbong.saas.domain.entity.ext.ContractEntityExt;
import com.xbongbong.saas.domain.entity.ext.OutstockEntityExt;
import com.xbongbong.saas.domain.entity.ext.PaymentSheetEntityExt;
import com.xbongbong.saas.domain.entity.ext.RefundEntityExt;
import com.xbongbong.saas.enums.ContractProductTypeEnum;
import com.xbongbong.saas.enums.OperateModuleTypeEnum;
import com.xbongbong.saas.enums.OperateTypeEnum;
import com.xbongbong.saas.enums.OutstockTypeEnum;
import com.xbongbong.saas.enums.SelectProductEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.ContractEnum;
import com.xbongbong.saas.enums.business.InvoiceEnum;
import com.xbongbong.saas.enums.business.OutstockEnum;
import com.xbongbong.saas.enums.business.PaymentSheetEnum;
import com.xbongbong.saas.enums.business.ProductEnum;
import com.xbongbong.saas.enums.business.RefundEnum;
import com.xbongbong.saas.enums.business.SerialEnum;
import com.xbongbong.saas.enums.business.SerialStatusEnum;
import com.xbongbong.saas.enums.dictionary.IsCancelEnum;
import com.xbongbong.saas.enums.dictionary.IsRedEnum;
import com.xbongbong.saas.enums.product.ContractProductEnum;
import com.xbongbong.saas.enums.product.RefundProductEnum;
import com.xbongbong.saas.enums.subform.ContractProductSubFormEnum;
import com.xbongbong.saas.model.ContractModel;
import com.xbongbong.saas.model.ContractPerformanceModel;
import com.xbongbong.saas.model.ContractProductModel;
import com.xbongbong.saas.model.ContractUserModel;
import com.xbongbong.saas.model.InstockModel;
import com.xbongbong.saas.model.InstockProductModel;
import com.xbongbong.saas.model.OutstockModel;
import com.xbongbong.saas.model.OutstockProductModel;
import com.xbongbong.saas.model.ProductSerialBalanceModel;
import com.xbongbong.saas.model.ProductSerialFlowModel;
import com.xbongbong.saas.model.RefundInvoiceModel;
import com.xbongbong.saas.model.RefundModel;
import com.xbongbong.saas.service.ListBatchService;
import com.xbongbong.saas.service.toolbox.help.LogHelp;
import com.xbongbong.saas.toolbox.help.FastJsonHelper;
import com.xbongbong.util.ProductUtil;
import com.xbongbong.workflow.domain.entity.WorkflowEntity;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.support.WriteRequest;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

import static com.xbongbong.saas.toolbox.help.FastJsonHelper.getDoubleOrDefaultFromFormData;
import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.index.query.QueryBuilders.termsQuery;

/**
 *
 * @author 魏荣杰
 *
 */
@Component
@Slf4j
public class RefundHelp {
    private static final Logger LOG = LoggerFactory.getLogger(RefundHelp.class);

    @Resource
    private ContractProductModel contractProductModel;
    @Resource
    private InstockModel instockModel;
    @Resource
    private ContractModel contractModel;
    @Resource
    private ContractUserModel contractUserModel;
    @Resource
    private ContractPerformanceModel contractPerformanceModel;
    @Resource
    private RefundModel refundModel;
    @Resource
    private PaasAppModel paasAppModel;
    @Resource
    private OutstockProductModel outstockProductModel;
    @Resource
    private OutstockModel outstockModel;
    @Resource
    private SaasProductHelp saasProductHelp;
    @Resource
    private EsHelper esHelper;
    @Resource
    private TransferSubFormHelper transferSubFormHelper;
    @Resource
    private ProductSerialFlowModel productSerialFlowModel;
    @Resource
    private ProductSerialBalanceModel productSerialBalanceModel;
    @Resource
    private XbbElasticsearchRestTemplate xbbElasticsearchRestTemplate;
    @Resource
    private InstockProductModel instockProductModel;
    @Resource
    private RefundInvoiceModel refundInvoiceModel;
    @Resource
    private WorkflowOperatorDataService workflowOperatorDataService;
    @Resource
    private ListBatchService listBatchService;
    @Resource
    private MongoLogHelp mongoLogHelp;
    @Resource
    private LogHelp logHelp;
    @Resource
    private WorkflowFormDataOperationService workflowFormDataOperationService;
    @Resource
    private CommonHelp commonHelp;
    @Resource
    private PaasFormModel paasFormModel;



    /**
     * 生成红冲合同及其关联表
     *
     * @param newPaasFormDataEntity 退货退款实体
     * @param contractEntityExt     合同
     * @param returnAmount          退货金额
     * @param productArray          产品
     * @param flowStatus            审批状态
     * @param isNew 是否新建
     * @return 红冲合同实体
     * @throws XbbException 异常
     */
    public RefundRedContractVO generateRedContract(PaasFormDataEntity newPaasFormDataEntity, ContractEntityExt contractEntityExt, Double returnAmount, JSONArray productArray, Integer flowStatus, Boolean isNew, UserVO userVO) throws XbbException {
        RefundRedContractVO refundRedContractVO = new RefundRedContractVO();
        if (contractEntityExt == null) {
            return refundRedContractVO;
        }
        if (Objects.isNull(productArray)) {
            productArray = new JSONArray();
        }
        String corpid = newPaasFormDataEntity.getCorpid();
        JSONObject refundData = newPaasFormDataEntity.getData();
        Long refundSign = FastJsonHelper.getLongOrDefaultFromFormData(refundData, RefundEnum.SIGN_DATE.getAttr() , 0L);
        JSONObject contractData = contractEntityExt.getData();
        Long contractId = contractEntityExt.getId();
        Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put(ParameterConstant.CORPID, corpid);
        param.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
        param.put(ParameterConstant.FLOW_STATUS_IN, Arrays.asList(FlowStatusEnum.NOT_NEED_APPROVAL.getType(), FlowStatusEnum.PASS.getType()));
        Integer redCount = instockModel.getCountByOneCondition(RefundEnum.CONTRACT_ID.getAttr(), contractId, param);
        String nameSuffix = I18nMessageUtil.getMessage(I18nStringConstant.REFUND);
        if (redCount > BasicConstant.ONE) {
            nameSuffix += redCount;
        }
        ContractEntityExt redContractEntity = new ContractEntityExt();
        BeanUtil.copyProperties(contractEntityExt, redContractEntity);
        redContractEntity.setId(null);
        redContractEntity.setSerialNo(newPaasFormDataEntity.getSerialNo());
        redContractEntity.setDel(DelEnum.NORMAL.getDel());
        redContractEntity.setFlowStatus(flowStatus);
        JSONObject redContractData = (JSONObject)contractData.clone();
        String name = FastJsonHelper.getStringOrDefaultFromFormData(contractData, ContractEnum.NAME.getAttr(), "");
        String status = FastJsonHelper.getStringOrDefaultFromFormData(contractData, ContractEnum.STATUS.getAttr(), "");
        redContractData.put(ContractEnum.NAME.getAttr(), name + nameSuffix);
        redContractData.put(ContractEnum.LINK_PARTNER_CUSTOMER.getAttr(), 0);
        redContractData.put(ContractEnum.LINK_PARTNER_CUSTOMER_HIDE.getAttr(), "");
        redContractData.put(ContractEnum.AMOUNT.getAttr(), -returnAmount);
        redContractData.put(ContractEnum.SIGN_TIME.getAttr(), refundSign);
        redContractData.put(ContractEnum.ARCHIVED.getAttr(), "");
        redContractData.put(ContractEnum.PAY_METHOD.getAttr(), "");
        redContractData.put(ContractEnum.IS_RED.getAttr(), BasicConstant.ONE);
        redContractData.put(ContractEnum.STATUS.getAttr(), status);
        if (productArray.isEmpty()) {
            redContractData.put(ContractEnum.ALL_OUT_BOUND.getAttr(), BasicConstant.ONE);
        }
        redContractEntity.setData(redContractData);
        try {
            contractModel.insert(redContractEntity);
        } catch (XbbException e) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }
        Long redContractId = redContractEntity.getId();
        JSONObject updateContractData = new JSONObject();
        updateContractData.put(ContractEnum.HAS_RED.getAttr(), BasicConstant.ONE);
        updateContractData.put(ContractEnum.IS_RED.getAttr(), BasicConstant.ZERO);
        UpdateDataEntity updateData = ExplainUtil.getUpdateData(contractEntityExt.getId(), updateContractData, corpid);
        contractModel.updateBatch(Collections.singletonList(updateData), corpid);
        refundData.put(RefundEnum.RED_CONTRACT_ID.getAttr(), redContractId.toString());
        JSONObject updateRefundData = new JSONObject();
        updateRefundData.put(RefundEnum.RED_CONTRACT_ID.getAttr(), redContractId.toString());
        if(productArray.isEmpty()){
            // 当退货退款单不关联产品时,不需要入库
            refundData.put(RefundEnum.ALL_IN_BOUND.getAttr(), BasicConstant.TWO);
            refundData.put(RefundEnum.REFUND_STATUS.getAttr(), RefundStatusEnum.UNREFUND.getCode());
            updateRefundData.put(RefundEnum.ALL_IN_BOUND.getAttr(), BasicConstant.TWO);
            updateRefundData.put(RefundEnum.REFUND_STATUS.getAttr(), RefundStatusEnum.UNREFUND.getCode());
        }
        // 合同销售团队
        param.remove(ParameterConstant.FLOW_STATUS_IN);
        param.put("contractId", contractEntityExt.getId());
        List<ContractUserEntity> contractUserEntityList = contractUserModel.findEntitys(param);
        Long now = DateTimeUtil.getInt();
        List<ContractUserEntity> insertBatchList = new ArrayList<>();
        for (ContractUserEntity cu : contractUserEntityList) {
            ContractUserEntity contractUserEntity = new ContractUserEntity();
            contractUserEntity.setDataId(redContractId);
            contractUserEntity.setCorpid(corpid);
            contractUserEntity.setUserId(cu.getUserId());
            contractUserEntity.setUserName(cu.getUserName());
            contractUserEntity.setUserAvatar(cu.getUserAvatar());
            contractUserEntity.setIsMain(cu.getIsMain());
            contractUserEntity.setDel(DelEnum.NORMAL.getDel());
            contractUserEntity.setAddTime(now);
            contractUserEntity.setUpdateTime(now);
            contractUserEntity.setCustomerId(cu.getCustomerId());
//            insertBatchList.add(contractUserEntity);
            contractUserModel.insert(contractUserEntity);
        }
//        contractUserModel.insertBatch(insertBatchList);
        List<ContractPerformanceEntity> contractPerformanceEntityList = contractPerformanceModel.findEntitys(param);
        List<ContractPerformanceEntity> insertPerformanceList = new ArrayList<>();
        for (ContractPerformanceEntity cp : contractPerformanceEntityList) {
            ContractPerformanceEntity contractPerformanceEntity = new ContractPerformanceEntity();
            contractPerformanceEntity.setContractId(redContractId);
            contractPerformanceEntity.setCorpid(corpid);
            contractPerformanceEntity.setUserId(cp.getUserId());
            contractPerformanceEntity.setUserName(cp.getUserName());
            contractPerformanceEntity.setUserAvatar(cp.getUserAvatar());
            contractPerformanceEntity.setIsSign(cp.getIsSign());
            contractPerformanceEntity.setRate(cp.getRate());
            contractPerformanceEntity.setDel(DelEnum.NORMAL.getDel());
            contractPerformanceEntity.setAddTime(now);
            contractPerformanceEntity.setUpdateTime(now);
            insertPerformanceList.add(contractPerformanceEntity);
        }

        if (CollectionsUtil.isNotEmpty(insertPerformanceList)) {
            contractPerformanceModel.insertBatch(insertPerformanceList, WriteRequest.RefreshPolicy.NONE);
            // 合同业绩分配操作日志
            OperateModuleTypeEnum operateModuleTypeEnum = OperateModuleTypeEnum.getByAlias(XbbRefTypeEnum.CONTRACT.getAlias());
            String opObjectName = I18nMessageUtil.getMessage(XbbRefTypeEnum.CONTRACT_PERFORMANCE.getName());
            String memo = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_ADD_WORK), userVO.getName(), XbbRefTypeEnum.CONTRACT.getName(), newPaasFormDataEntity.getSerialNo(), opObjectName);
            List<ContractPerformanceLogPojo> performanceLogPojoList = new ArrayList<>(insertPerformanceList.size());
            insertPerformanceList.forEach(item -> {
                ContractPerformanceLogPojo logPojo = new ContractPerformanceLogPojo();
                logPojo.setNewEntity(item);
                performanceLogPojoList.add(logPojo);
            });
            try {
                List<DetailLogComplexPojo> detailArr = logHelp.detailLog4ContractPerformance(performanceLogPojoList);
                mongoLogHelp.buildLog4ComplexDetailArr(detailArr, userVO.getCorpid(), userVO.getUserId(), userVO.getName(), operateModuleTypeEnum, OperateTypeEnum.NEW, redContractId.toString(), opObjectName, memo, "");
            } catch (Exception e) {
                LOG.error("生成红冲合同的业绩分配日志记录失败！", e);
            }
        }

        JSONArray deepCloneProductArray = new JSONArray();

        if (isNew && !productArray.isEmpty()) {
            deepCloneProductArray = (JSONArray) CloneUtil.deepClone(productArray);
            Long refundLinkContractId = refundData.getLong(RefundEnum.CONTRACT_ID.getAttr());
            // 保存产品
            saveProduct(productArray, corpid, redContractId, refundLinkContractId, isNew);
            // 当退货退款单不关联产品时,未入库
            refundData.put(RefundEnum.ALL_IN_BOUND.getAttr(), BasicConstant.ZERO);
            refundData.put(RefundEnum.REFUND_STATUS.getAttr(), RefundStatusEnum.UNREFUND.getCode());
            updateRefundData.put(RefundEnum.ALL_IN_BOUND.getAttr(), BasicConstant.ZERO);
            updateRefundData.put(RefundEnum.REFUND_STATUS.getAttr(), RefundStatusEnum.UNREFUND.getCode());
        }
        // 更新红冲合同的合同成本，合同毛利，现金毛利(包含新建和编辑)
        updateRedContract(productArray,corpid,redContractEntity,contractEntityExt,refundData,returnAmount,isNew, newPaasFormDataEntity.getId());

        SaveFormatHelp.formatSelectProduct4Save2(refundData,RefundEnum.PRODUCTS.getAttr());
        updateRefundData.put(RefundEnum.PRODUCTS.getAttr(), refundData.get(RefundEnum.PRODUCTS.getAttr()));
        newPaasFormDataEntity.setData(refundData);
        RefundEntityExt refundEntityExt = new RefundEntityExt();
        BeanUtils.copyProperties(newPaasFormDataEntity, refundEntityExt);
        // TODO: 2020/11/4 不更新子表单
        List<UpdateDataEntity> list = new ArrayList<>();
        list.add(ExplainUtil.getUpdateData(newPaasFormDataEntity.getId(), updateRefundData, corpid));
        refundModel.updateBatch(list, corpid);
        // 保存序列号
        if (isNew && !productArray.isEmpty()) {
            saveSerial(refundEntityExt, deepCloneProductArray);
        }
        refundRedContractVO.setContractEntityExt(redContractEntity);
        refundRedContractVO.setCloneProductArr(deepCloneProductArray);
        return refundRedContractVO;
    }



    private void saveProduct(JSONArray productArray, String corpid, Long redContractId, Long refundLinkContractId, Boolean isNew) throws XbbException {
        //折扣，取合同的
        Map<Long, PaasFormDataEntityExt> productMap = saasProductHelp.product2saveMap(corpid,productArray);
        Integer sort = 0;
        Map<Long, Double> refundNumMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long, Double> refundProductNumMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long, Double> allOldrefundNumMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        List<ContractProductEntity> contractProductEntityList = new ArrayList(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Integer, JSONArray> seqArrayMap = new HashMap<>(productArray.size());
        for (int i = 0; i < productArray.size(); i++) {
            JSONObject jsonObject = productArray.getJSONObject(i);
            JSONArray seqArray = jsonObject.getJSONArray(ProductConstant.SEQ);
            // 移除序列号相关数据，不存入关联产品数据中
            jsonObject.remove(ProductConstant.SEQ);
            jsonObject.remove(ProductEnum.ENABLE_SERIAL_NUMBER.getSaasAttr());
            jsonObject.remove(ProductEnum.ENABLE_BATCH_SHELF_LIFE.getSaasAttr());

            Long pageProductId = jsonObject.getLong(SelectProductEnum.PRODUCT.getAttr());
            Long refProductId = jsonObject.getLong(BusinessConstant.REF_PRODUCT_ID);
            sort++;
            Double productNum = jsonObject.getDouble(ContractProductEnum.NUM.getAttr());
            Double price = jsonObject.getDouble(RefundProductEnum.PRICE.getAttr());
            price = price != null ? price : 0;
            // 折扣：默认为100%
            Double discount = jsonObject.getDouble(ContractProductEnum.DISCOUNT.getAttr());
            discount = discount == null ? 100 : discount;
            // 备注
            String memo = jsonObject.getString(ContractProductEnum.MEMO.getAttr());
            Double businessUnitPrice = FastJsonHelper.getJsonArrOrDefaultFromFormData(jsonObject, ProductConstant.PRICE, new JSONArray()).toJavaList(MultiUnitPricePoJo.class).stream().collect(Collectors.toMap(MultiUnitPricePoJo::getValue, MultiUnitPricePoJo::getRate)).get(jsonObject.getLong(SelectProductEnum.BUSINESS_UNIT.getAttr()));
            JSONObject productData = productMap.get(pageProductId).getData();
            ContractProductEntity contractProductEntity = new ContractProductEntity();
            contractProductEntity.setCorpid(corpid);
            contractProductEntity.setContractId(redContractId);
            contractProductEntity.setParentId(productData.getLong(ProductEnum.PARENT_ID.getAttr()));
            contractProductEntity.setProductId(pageProductId);
            contractProductEntity.setProductNum(-productNum);
            contractProductEntity.setProductName(productData.getString(ProductEnum.NAME.getAttr()));
            contractProductEntity.setProductNo(productData.getString(ProductEnum.PRODUCT_NO.getAttr()));
            contractProductEntity.setPrice(price);
            contractProductEntity.setDiscount(discount);
            contractProductEntity.setSpecification(productData.getString(ProductEnum.SPECIFICATION_LINK_TEXT.getAttr()));
            contractProductEntity.setContractOutstockNum(0D);
            contractProductEntity.setInstockNum(0D);
            // TODO 这里不应该有为空的情况
            if (Objects.nonNull(refProductId)) {
                contractProductEntity.setRefProductId(refProductId);
                refundNumMap.put(refProductId, productNum);
                Double num = refundProductNumMap.getOrDefault(pageProductId, 0D);
                num += productNum;
                refundProductNumMap.put(pageProductId, num);
            }else {
                Double num = allOldrefundNumMap.getOrDefault(pageProductId, 0D);
                num += productNum;
                allOldrefundNumMap.put(pageProductId, num);
            }
            contractProductEntity.setMemo(memo);
            contractProductEntity.setBarcode(productData.getString(ProductEnum.BARCODE.getAttr()));
            contractProductEntity.setCost(jsonObject.getDouble(SelectProductEnum.COST.getAttr()));
            if (Objects.nonNull(businessUnitPrice)) {
                productData.put(ProductEnum.PRICE.getAttr(),businessUnitPrice);
            }
            contractProductEntity.setHistoricalPrice(productData.getDouble(ProductEnum.PRICE.getAttr()));
            contractProductEntity.setSort(sort);
            contractProductEntity.setType(ContractProductTypeEnum.REFUND.getCode());
            Integer enableMultiUnit = productData.getInteger(ProductEnum.ENABLE_MULTI_UNIT.getAttr());
            if (Objects.equals(enableMultiUnit, 1)) {
                ProductUtil.setBusinessUnit(jsonObject, contractProductEntity);
                contractProductEntity.setProductUnit(jsonObject.getString(SelectProductEnum.UNIT.getAttr()));
            } else {
                contractProductEntity.setProductUnit(productData.getString(ProductEnum.UNIT.getAttr()));
                jsonObject.put(SelectProductEnum.UNIT.getAttr(),productData.getString(ProductEnum.UNIT.getAttr()));
            }
            contractProductEntity.setData(jsonObject);
            contractProductEntityList.add(contractProductEntity);
//            contractProductModel.insert(contractProductEntity);
            //
            if (Objects.nonNull(seqArray) && !seqArray.isEmpty()) {
//                jsonObject.put(ProductConstant.SEQ, seqArray);
                seqArrayMap.put(i, seqArray);
            }
        }
        contractProductModel.insertBatch(contractProductEntityList);

        // TODO lee 只写了一种逻辑
        PaasAppEntity paasAppEntity = paasAppModel.getByAlias(XbbRefTypeEnum.JXC.getAlias(), corpid);
        boolean isOpenJxc = false;
        if (Objects.nonNull(paasAppEntity)) {
            isOpenJxc = paasAppEntity.getEnable() == 1;
        }
        if (isOpenJxc) {
            if (!refundNumMap.isEmpty()) {
                Map<String, Object> params = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                params.put("corpid", corpid);
                params.put("idIn", refundNumMap.keySet());
                params.put("del", DelEnum.NORMAL.getDel());
                List<OutstockProductEntity> outstockProductEntities = outstockProductModel.findEntitys(params);
                Map<Long, Double> refundNumsMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                HashSet<Long> oldOutstockIds = new HashSet<>();
                outstockProductEntities.forEach(item -> {
                    if (Objects.nonNull(item.getRefProductId()) && refundNumMap.containsKey(item.getId())) {
                        item.setInstockNum(Arith.add(item.getInstockNum() == null ? 0D : item.getInstockNum(), refundNumMap.get(item.getId())));
                        refundNumsMap.put(item.getRefProductId(), Arith.add(refundNumsMap.getOrDefault(item.getRefProductId(), 0D), refundNumMap.get(item.getId())));
                    }else {
//                        老数据逻辑
                        oldOutstockIds.add(item.getOutWarehouseId());
                    }
                });
                outstockProductModel.updateBatch(outstockProductEntities, corpid);
                if (!refundNumsMap.isEmpty()) {
                    params.put("idIn", refundNumsMap.keySet());
                    List<ContractProductEntity> contractProductEntities = contractProductModel.findEntitys(params);
                    contractProductEntities.forEach(item -> {
                        if (refundNumsMap.containsKey(item.getId())) {
                            item.setInstockNum(Arith.add(item.getInstockNum(), refundNumsMap.get(item.getId())));
                        }
                    });
                    contractProductModel.updateBatch(contractProductEntities, corpid);
                }
                if (!oldOutstockIds.isEmpty()) {
                    HashSet<Long> contractIds = new HashSet<>();
                    params.put("idIn", oldOutstockIds);
                    List<OutstockEntityExt> entitys = outstockModel.findEntitys(params);
                    entitys.forEach(item -> {
                        Long contractId = item.getData().getLong(OutstockEnum.REF_ID.getAttr());
                        contractIds.add(contractId);
                    });
                    if (!contractIds.isEmpty()) {
                        params.clear();
                        params.put("corpid", corpid);
                        params.put("contractIdIn", contractIds);
                        params.put("del", DelEnum.NORMAL.getDel());
                        List<ContractProductEntity> contractProductEntities = contractProductModel.findEntitys(params);
                        for (ContractProductEntity entity : contractProductEntities) {
                            if (refundProductNumMap.containsKey(entity.getProductId())) {
                                // 剩余未退
                                Double unStockNum = Arith.sub(entity.getProductNum(), entity.getInstockNum());
                                Double amendNum = refundProductNumMap.get(entity.getProductId());
                                Double instockNum;
                                Double inNum = Arith.sub(amendNum, unStockNum);
                                if (inNum > 0) {
                                    instockNum = entity.getProductNum();
                                    refundProductNumMap.put(entity.getProductId(), inNum);
                                }else {
                                    instockNum = Arith.add(entity.getInstockNum(), amendNum);
                                    refundProductNumMap.remove(entity.getProductId());
                                }
                                entity.setInstockNum(instockNum);
                                entity.setUpdateTime(DateTimeUtil.getInt());
                            }
                        }
                        contractProductModel.updateBatch(contractProductEntities, corpid);
                    }
                }
            }
            if (!allOldrefundNumMap.isEmpty()) {
//             退货退款没有refproductid的情况
                Map<String, Object> params = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                params.put("corpid", corpid);
                params.put("contractId", refundLinkContractId);
                params.put("del", DelEnum.NORMAL.getDel());
                List<ContractProductEntity> contractProductEntities = contractProductModel.findEntitys(params);
                contractProductEntities.forEach(item ->{
                    if (allOldrefundNumMap.containsKey(item.getProductId())) {
                        // 剩余未退
                        Double unStockNum = Arith.sub(item.getProductNum(), item.getInstockNum());
                        Double amendNum = allOldrefundNumMap.get(item.getProductId());
                        Double instockNum;
                        Double inNum = Arith.sub(amendNum, unStockNum);
                        if (inNum > 0) {
                            instockNum = item.getProductNum();
                            allOldrefundNumMap.put(item.getProductId(), inNum);
                        }else {
                            instockNum = Arith.add(item.getInstockNum(), amendNum);
                            allOldrefundNumMap.remove(item.getProductId());
                        }
                        item.setInstockNum(instockNum);
                        item.setUpdateTime(DateTimeUtil.getInt());
                    }
                });
                contractProductModel.updateBatch(contractProductEntities, corpid);
            }
        }else {
            if (!refundNumMap.isEmpty()) {
                Map<String, Object> params = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                params.put("corpid", corpid);
                params.put("idIn", refundNumMap.keySet());
                params.put("del", DelEnum.NORMAL.getDel());
                List<ContractProductEntity> contractProductEntities = contractProductModel.findEntitys(params);
                contractProductEntities.forEach(item -> {
                    if (refundNumMap.containsKey(item.getId())) {
                        item.setInstockNum(Arith.add(item.getInstockNum(), refundNumMap.get(item.getId())));
                    }
                });
                contractProductModel.updateBatch(contractProductEntities, corpid);
            }
        }
    }


    /**
     * 更新红冲合同的合同成本，合同毛利，现金毛利
     * @param productArray
     * @param corpid
     * @param redContractEntity
     * @param contractEntityExt
     * @param refundData
     * @param returnAmount
     * @throws XbbException
     */
    public void updateRedContract(JSONArray productArray, String corpid, ContractEntityExt redContractEntity, ContractEntityExt contractEntityExt, JSONObject refundData, Double returnAmount, Boolean isNew, Long refundId) throws XbbException {
        JSONObject redContractData = redContractEntity.getData();
        JSONObject contractData = contractEntityExt.getData();
        Long contractId = contractEntityExt.getId();

        boolean isOpenJxc = ifJXCOpen(corpid);
        // 计算红冲合同的总成本(无产品退货退款时，这个红冲合同的总成本直接默认0)
        Double redContractCost = 0D;
        Map<Long, Double> productIdAndNumMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long, Double> webProductIdAndNumMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<String, Double> batchProductIdAndNumMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if (!productArray.isEmpty()) {
            for (int i = 0; i < productArray.size(); i++) {
                JSONObject jsonObject = productArray.getJSONObject(i);
                Long pageProductId = jsonObject.getLong(SelectProductEnum.PRODUCT.getAttr());
                Double productNum = jsonObject.getDouble(ContractProductEnum.NUM.getAttr());
                String batchNum = jsonObject.getString(RefundProductEnum.BATCH.getAttr());
                String key = pageProductId.toString();
                if(StringUtils.isNotEmpty(batchNum)){
                    key = key+batchNum;
                }
                if(batchProductIdAndNumMap.containsKey(key)){
                    productNum = Arith.add(batchProductIdAndNumMap.get(key), productNum);
                }
                batchProductIdAndNumMap.put(key,productNum);
                // 退货产品ID以及对应的数量
                if(productIdAndNumMap.containsKey(pageProductId)){
                    productNum = Arith.add(productIdAndNumMap.get(pageProductId), productNum);
                }
                productIdAndNumMap.put(pageProductId, -productNum);

                webProductIdAndNumMap.put(pageProductId, productNum);
            }

            // 开启进销存是直接查询原合同关联的出库单产品成本(同一件产品多次出库，就是每次相加出库成本*每次出库数量/总出库数量)*红冲合同产品表的产品数量(退货产品数量)
            if(isOpenJxc){
                List<Long> outstockIdList = FastJsonHelper.getJsonArrOrDefaultFromFormData(contractData, ContractEnum.OUTSTOCK_ID.getAttr(), new JSONArray()).toJavaList(Long.class);
                if (!outstockIdList.isEmpty()) {
                    Map<String,Object> outstockParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    outstockParam.put("corpid", corpid);
                    outstockParam.put("del", DelEnum.NORMAL.getDel());
                    outstockParam.put("outstockIdIn", outstockIdList);
                    List<OutstockProductEntity> outstockProductList = outstockProductModel.findEntitys(outstockParam);
                    Map<Long, OutstockProductEntity> outstockProductEntityMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    // 算出每个产品对应的成本
                    Map<String, Double> batchProductIdAndCostMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    // 所有的出库记录
                    for (OutstockProductEntity outstockProductEntity : outstockProductList) {
                        Long productId = outstockProductEntity.getProductId();
                        Double productNum = outstockProductEntity.getProductNum() == null ? 0D : outstockProductEntity.getProductNum();
                        Double productCost = outstockProductEntity.getCost() == null ? 0D : outstockProductEntity.getCost();
                        String batchNum = outstockProductEntity.getBatch();
                        String key = productId.toString();
                        if(StringUtils.isNotEmpty(batchNum)) {
                            key = key + batchNum;
//                            batchProductIdAndNumMap.put(key, productNum);
                        }
                        batchProductIdAndCostMap.put(key, productCost);
                    }
                    // 遍历红冲合同
                    Iterator iterator = batchProductIdAndNumMap.keySet().iterator();
                    while (iterator.hasNext()) {
                        String key = iterator.next().toString();
                        Double productNum = batchProductIdAndNumMap.get(key);
                        if(batchProductIdAndCostMap.containsKey(key)){
                            // 取负
                            redContractCost = Arith.add(redContractCost, Arith.mul(productNum, -batchProductIdAndCostMap.get(key)));
                        }
                    }
                }
            } else {
                // 不开启进销存是直接查询原合同关联产品表的成本*红冲合同产品表的产品数量(退货产品数量)
                BoolQueryBuilder boolQueryBuilder = boolQuery();
                boolQueryBuilder.filter(termQuery("corpid.keyword",corpid));
                boolQueryBuilder.filter(termQuery(StringConstant.DEL,DelEnum.NORMAL.getDel()));
                boolQueryBuilder.filter(termQuery(ContractProductSubFormEnum.getEsAttr(ContractProductSubFormEnum.TYPE),201));
                boolQueryBuilder.filter(termQuery(ContractProductSubFormEnum.getEsAttr(ContractProductSubFormEnum.CONTRACT_ID), contractId));
                List<String> fieldList = Arrays.asList(ContractProductSubFormEnum.getAttrConnectData(ContractProductSubFormEnum.PRODUCT_ID) , ContractProductSubFormEnum.getAttrConnectData(ContractProductSubFormEnum.CONTRACT_ID), ContractProductSubFormEnum.getAttrConnectData(ContractProductSubFormEnum.PRODUCT_NUM), ContractProductSubFormEnum.getAttrConnectData(ContractProductSubFormEnum.PRICE), ContractProductSubFormEnum.getAttrConnectData(ContractProductSubFormEnum.COST));
                List<PaasFormDataEntity> list =  esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_CONTRACT_PRODUCT,boolQueryBuilder,PaasFormDataEntity.class, fieldList);
                if(list.size() > 0) {
                    List<ContractProductEntity> contractProductEntities = transferSubFormHelper.transferFormDataToContractProductList(list);
                    for (ContractProductEntity contractProductEntity : contractProductEntities) {
                        Long productId = contractProductEntity.getProductId();
                        Double cost = contractProductEntity.getCost() == null ? 0D : contractProductEntity.getCost();
                        if(productIdAndNumMap.containsKey(productId)){
                            Double productCost = Arith.mul(cost, productIdAndNumMap.get(productId));
                            redContractCost = Arith.add(redContractCost, productCost);
                        }
                    }
                }
            }
        }

        // 更新红冲合同的合同成本，合同毛利，现金毛利
        redContractData.put(ContractEnum.CONTRACT_COST.getAttr(), redContractCost);
        redContractData.put(ContractEnum.GROSS_PROFIT.getAttr(), Arith.sub(-returnAmount, redContractCost));
        Double refundAmount = getDoubleOrDefaultFromFormData(refundData, RefundEnum.REFUND_AMOUNT.getAttr() , 0D);
        redContractData.put(ContractEnum.CASH_PROFIT.getAttr(), Arith.sub(-refundAmount, redContractCost));
        // 补充一下更新签订日期
        Long refundSign = FastJsonHelper.getLongOrDefaultFromFormData(refundData, RefundEnum.SIGN_DATE.getAttr(), 0L);
        redContractData.put(ContractEnum.SIGN_TIME.getAttr(), refundSign);
        // 补充更新一下红冲合同金额
        redContractData.put(ContractEnum.AMOUNT.getAttr(), -returnAmount);

        redContractEntity.setData(redContractData);
        contractModel.update(redContractEntity);

        // 直接重新计算数据比较精确
        resetOldContractData(corpid, contractEntityExt, isOpenJxc, webProductIdAndNumMap, isNew, returnAmount, refundId);
    }


    public boolean ifJXCOpen(String corpid) throws XbbException {
        PaasAppEntity paasAppEntity = paasAppModel.getByAlias(XbbRefTypeEnum.JXC.getAlias(), corpid);
        Integer enable;
        if (paasAppEntity == null) {
            log.error("RefundServiceImpl 该公司进销存业务没有数据" + corpid);
            // 默认关闭
            enable = BasicConstant.ZERO;
        } else {
            enable = paasAppEntity.getEnable();
        }
        return Objects.equals(BasicConstant.ONE, enable);
    }


    private void saveSerial(RefundEntityExt refundEntityExt, JSONArray deepCloneProductArray) throws XbbException {
        JSONObject refundData = refundEntityExt.getData();
        String corpid = refundEntityExt.getCorpid();
        Long refundId = refundEntityExt.getId();
        // 红冲合同
        Long redContractId = refundData.getLong(RefundEnum.RED_CONTRACT_ID.getAttr());
        List<ContractProductEntity> linkProductEntities = contractProductModel.getProductsByConId(redContractId, corpid);
        List<ProductSerialFlowEntity> productSerialFlowEntityList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<String, ProductSerialFlowEntity> productSerialFlowEntityMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Set<String> seqKeyList = new HashSet<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        //
        List<ProductSerialFlowEntity> flowEntityList = productSerialFlowModel.getFlowByRefIdAndBusiness(Collections.singletonList(refundId), XbbRefTypeEnum.REFUND.getCode(), corpid);
        List<String> serialList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if (CollectionUtils.isNotEmpty(flowEntityList)) {
            flowEntityList.forEach(item -> serialList.add(item.getSeqKey()));
        }
        for (int i = 0; i < deepCloneProductArray.size(); i++) {
            JSONObject productData = deepCloneProductArray.getJSONObject(i);
            JSONArray seqArray = productData.getJSONArray(ProductConstant.SEQ);
            ContractProductEntity linkProductEntity = linkProductEntities.get(i);
            productData.put(BusinessConstant.PRODUCT_SUB_ID, linkProductEntity.getId());
            if (BasicConstant.ZERO.equals(productData.getIntValue(ProductEnum.ENABLE_SERIAL_NUMBER.getSaasAttr())) && (Objects.isNull(seqArray) || seqArray.isEmpty())) {
                continue;
            }
            Long productId = productData.getLong(RefundProductEnum.PRODUCT.getAttr());
            for (int j = 0; j < seqArray.size(); j++) {
                JSONObject seqData = seqArray.getJSONObject(j);
                String serial = seqData.getString(SerialEnum.SERIAL.getAttr());
                String seqKey = productId + "_" + serial;
                if (serialList.contains(seqKey)) {
                    throw new XbbException(ProductErrorCodeEnum.API_ERROR_205094, String.format(ProductErrorCodeEnum.API_ERROR_205094.getMsg(), serial));
                }
                ProductSerialFlowEntity productSerialFlowEntity = new ProductSerialFlowEntity();
                productSerialFlowEntity.setCorpid(corpid);
                productSerialFlowEntity.setProductId(productId);
                productSerialFlowEntity.setSeq(serial);
                productSerialFlowEntity.setMemo(seqData.getString(SerialEnum.MEMO.getAttr()));
                productSerialFlowEntity.setStatus(SerialStatusEnum.OUT_STOCK.getCode());
                productSerialFlowEntity.setDate(DateTimeUtil.getInt());
                productSerialFlowEntity.setBusinessType(XbbRefTypeEnum.REFUND.getCode());
                productSerialFlowEntity.setRefId(refundId);
                productSerialFlowEntity.setRefSheetNo(refundEntityExt.getSerialNo());
                // 关联产品id
                productSerialFlowEntity.setRefProductId(linkProductEntity.getId());
                productSerialFlowEntity.setParentId(linkProductEntity.getParentId());
                productSerialFlowEntity.setBusinessId(refundData.getLong(RefundEnum.CUSTOMER_ID.getAttr()));
                productSerialFlowEntity.setBusinessName(refundData.getString(RefundEnum.CUSTOMER_ID_LINKED_TEXT.getAttr()));
                productSerialFlowEntity.setSeqKey(seqKey);
                productSerialFlowEntity.setDel(BasicConstant.ZERO);

                seqKeyList.add(productSerialFlowEntity.getSeqKey());
                productSerialFlowEntityList.add(productSerialFlowEntity);
                productSerialFlowEntityMap.put(productSerialFlowEntity.getSeqKey(), productSerialFlowEntity);
            }
        }
        if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(productSerialFlowEntityList)) {
            Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            param.put("corpid", corpid);
            param.put("seqKeyIn", seqKeyList);
            param.put(StringConstant.DEL, DelEnum.NORMAL.getDel());
            // 结存记录
            List<ProductSerialBalanceEntity> entitys = productSerialBalanceModel.findEntitys(param);
            for (ProductSerialBalanceEntity entity : entitys) {
                ProductSerialFlowEntity productSerialFlowEntity = productSerialFlowEntityMap.get(entity.getSeqKey());
                entity.setStatus(productSerialFlowEntity.getStatus());
                entity.setBusinessType(productSerialFlowEntity.getBusinessType());
                entity.setRefId(productSerialFlowEntity.getRefId());
                entity.setRefProductId(productSerialFlowEntity.getRefProductId());
                entity.setDate(productSerialFlowEntity.getDate());
                entity.setRefSheetNo(productSerialFlowEntity.getRefSheetNo());
                // 反向操作一波，仓库不变
                productSerialFlowEntity.setWarehouseId(entity.getWarehouseId());
            }
            // 新增流水
            productSerialFlowModel.insertBatch(productSerialFlowEntityList);
            // 更新结存
            productSerialBalanceModel.updateBatch(entitys, corpid);
        }
    }

    /**
     * 直接重新计算数据比较精确
     * @param corpid
     * @param contractEntityExt
     * @param isOpenJxc
     * @throws XbbException
     */
    private void resetOldContractData(String corpid, ContractEntityExt contractEntityExt, boolean isOpenJxc, Map<Long, Double> webProductIdAndNumMap, boolean isNew, Double returnAmount, Long refundId) throws XbbException{
        JSONObject contractData = contractEntityExt.getData();
        JSONObject updateContractData = new JSONObject();
        Long contractId = contractEntityExt.getId();
        // 查询出所有关联原合同的退货金额(一对多)
        Map<Long, Double> allContractCostMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);

        // 合同与红冲合同对应map
        Map<Long, List<Long>> contractIdAndRedContractMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);

        // 合同与入库单对应map
        Map<Long, List<Long>> contractIdAndInstockIdMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);

        BoolQueryBuilder oldQueryBuilder = boolQuery();
        oldQueryBuilder.filter(termQuery("corpid.keyword",corpid));
        oldQueryBuilder.filter(termsQuery(RefundEnum.getEsAttr4Keyword(RefundEnum.CONTRACT_ID),Arrays.asList(contractId)));
        oldQueryBuilder.filter(termQuery(StringConstant.DEL,DelEnum.NORMAL.getDel()));
        oldQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, IndexTypeEnum.IDX_SAAS_REFUND.getType()));
        SearchSourceBuilder builder = new SearchSourceBuilder();
        builder.query(oldQueryBuilder);
        PageRequest page = EsUtil.setPage(builder, 1, PaasConstant.ES_MAX_PAGE_SIZE);
        SearchRequest search = new SearchRequest(IndexTypeEnum.IDX_SAAS_REFUND.getIndex());
        search.source(builder);
        XbbAggregatedPage<PaasFormDataEntity> entities = xbbElasticsearchRestTemplate.queryForPages(page, search, PaasFormDataEntity.class);
        Boolean sumSelf = false;
        for (PaasFormDataEntity entity : entities.getContent()) {
            JSONObject data = entity.getData();
            Double returnCost = FastJsonHelper.getDoubleOrDefaultFromFormData(data, RefundEnum.RETURN_AMOUNT.getAttr(), 0D);

            if (Objects.equals(entity.getDataId(), refundId)) {
                // 用于判断当前新建的退货退款是否进入了es，避免下方出现重复累加的问题
                sumSelf = true;
            }
            // 统计所有的退货金额
            if(allContractCostMap.containsKey(contractId)){
                Double cost = allContractCostMap.get(contractId) == null ? 0D : allContractCostMap.get(contractId);
                returnCost = Arith.add(returnCost, cost);
                allContractCostMap.put(contractId, returnCost);
            } else {
                allContractCostMap.put(contractId, returnCost);
            }

            // 合同与红冲合同对应关系
            Long redConId = data.getLong(RefundEnum.RED_CONTRACT_ID.getAttr());
            if(contractIdAndRedContractMap.containsKey(contractId)){
                List<Long> redConIdList = contractIdAndRedContractMap.get(contractId) == null ? new ArrayList<>() : contractIdAndRedContractMap.get(contractId);
                List<Long> idList = new ArrayList<>(redConIdList);
                idList.add(redConId);
                contractIdAndRedContractMap.put(contractId, idList);
            } else {
                contractIdAndRedContractMap.put(contractId, Arrays.asList(redConId));
            }

            // 合同与入库单对应关系
            JSONArray instockIdArr = FastJsonHelper.getJsonArrOrDefaultFromFormData(data, RefundEnum.INSTOCK_ID.getAttr(), new JSONArray());
            if(!instockIdArr.isEmpty()){
                List<Long> instocks = instockIdArr.toJavaList(Long.class);
                if(contractIdAndInstockIdMap.containsKey(contractId)){
                    List<Long> instockList = contractIdAndInstockIdMap.get(contractId) == null ? new ArrayList<>() : contractIdAndInstockIdMap.get(contractId);
                    List<Long> idList = new ArrayList<>(instockList);
                    idList.addAll(instocks);
                    contractIdAndInstockIdMap.put(contractId, idList);
                } else {
                    contractIdAndInstockIdMap.put(contractId, instocks);
                }
            }
        }

        // 查询出所有关联原合同的出库单
        Map<Long, List<Long>> allContractOutMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        // 所有对应的合同实体
        List<ContractEntityExt> contractList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        List<Long> contractIdList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        BoolQueryBuilder entityQueryBuilder = boolQuery();
        entityQueryBuilder.filter(termQuery("corpid.keyword", corpid));
        entityQueryBuilder.filter(termsQuery(FieldTypeEnum.DATAID.getAlias(), Arrays.asList(contractId)));
        entityQueryBuilder.filter(termQuery("del", 0));
        entityQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, IndexTypeEnum.IDX_SAAS_CONTRACT.getType()));
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.query(entityQueryBuilder);
        PageRequest pageRequest = EsUtil.setPage(sourceBuilder, 1, 1);
        SearchRequest searchRequest = new SearchRequest(IndexTypeEnum.IDX_SAAS_CONTRACT.getIndex());
        searchRequest.source(sourceBuilder);
        XbbAggregatedPage<ContractEntityExt> esEntities = xbbElasticsearchRestTemplate.queryForPages(pageRequest, searchRequest, ContractEntityExt.class);
        for (ContractEntityExt entity : esEntities.getContent()) {
            contractList.add(entity);
            contractIdList.add(contractId);

            JSONObject data = entity.getData();
            List<Long> outstockIdList = FastJsonHelper.getJsonArrOrDefaultFromFormData(data, ContractEnum.OUTSTOCK_ID.getAttr(), new JSONArray()).toJavaList(Long.class);

            if(allContractOutMap.containsKey(contractId)){
                List<Long> outIdList = allContractOutMap.get(contractId) == null ? new ArrayList<>() : allContractOutMap.get(contractId);
                List<Long> outIdIn = new ArrayList<>(outIdList);
                outIdIn.addAll(outstockIdList);
                allContractOutMap.put(contractId, outIdIn);
            } else {
                allContractOutMap.put(contractId, outstockIdList);
            }
        }

        Double jxc2UpdateInstockCost = BasicConstant.ZERO_DOUBLE;

        // 查询该合同对应所有入库单的产品
        List<Long> instockList = contractIdAndInstockIdMap.get(contractId) == null ? new ArrayList<>() : contractIdAndInstockIdMap.get(contractId);
        //入库单的产品id及其数量
        Map<Long, Double> instockProductIdAndNum = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if(!instockList.isEmpty()){
            Map<String,Object> instockProductParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            instockProductParam.put("corpid", corpid);
            instockProductParam.put("instockIdIn",instockList);
            instockProductParam.put("del", 0);
            List<InstockProductEntity> instockProductEntityList = instockProductModel.findEntitys(instockProductParam);
            for(InstockProductEntity instockPro : instockProductEntityList){
                // 新数据计算，直接计算所有该合同所有入库单的成本
                Double productNum = instockPro.getProductNum() == null ? 0D : Math.abs(instockPro.getProductNum());
                Double productCost = instockPro.getCost() == null ? 0D : instockPro.getCost();
                jxc2UpdateInstockCost = Arith.add(jxc2UpdateInstockCost, Arith.mul(productNum, productCost));

                // 统计入库单每一件产品的数量
                Long productId = instockPro.getProductId();
                Double num = instockPro.getProductNum();
                if(instockProductIdAndNum.containsKey(productId)){
                    Double inNum = instockProductIdAndNum.get(productId) == null ? BasicConstant.ZERO_DOUBLE : instockProductIdAndNum.get(productId);
                    Double countNum = Arith.add(inNum, num);
                    instockProductIdAndNum.put(productId, countNum);
                } else {
                    instockProductIdAndNum.put(productId, num);
                }
            }
        }

        // 合同与红冲合同退货产品成本对应map
        Map<Long, Double> contractIdAndCostMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);

        // 查询所有的红冲合同
        Iterator entries = contractIdAndRedContractMap.entrySet().iterator();
        while(entries.hasNext()){
            Map.Entry entry = (Map.Entry) entries.next();
            Long key = (Long) entry.getKey();
            List<Long> redConIdList = contractIdAndRedContractMap.get(key);
            Double costAmount = BasicConstant.ZERO_DOUBLE;
            if(redConIdList.size() > 0) {
                Map<Long, Double> productIdAndNumMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                Map<String,Object> redParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                redParam.put("corpid", corpid);
                redParam.put("contractIdIn",redConIdList);
                redParam.put("del", 0);
                // 拿到红冲合同的所有产品
                List<ContractProductEntity> contractProductEntityList = contractProductModel.findEntitys(redParam);

                // 退货产品ID以及对应的数量
                for(ContractProductEntity entity : contractProductEntityList){
                    Long pageProductId = entity.getProductId();
                    Double productNum = entity.getProductNum() == null ? 0D : Math.abs(entity.getProductNum());
                    if(productIdAndNumMap.containsKey(pageProductId)){
                        Double num = productIdAndNumMap.get(pageProductId) == null ? 0D : productIdAndNumMap.get(pageProductId);
                        productNum = Arith.add(productNum, num);
                    }
                    productIdAndNumMap.put(pageProductId, productNum);
                }

                // 新建的时候，红冲合同产品这一步还没有入库，需要直接取前端的数据
                if(isNew && !webProductIdAndNumMap.isEmpty()){
                    if(productIdAndNumMap.isEmpty()){
                        productIdAndNumMap.putAll(webProductIdAndNumMap);
                    } else {
                        Map<Long, Double> webMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                        Iterator productIterator = productIdAndNumMap.keySet().iterator();
                        while (productIterator.hasNext()) {
                            Long id = Long.valueOf(productIterator.next().toString());
                            Double productNum = productIdAndNumMap.get(id);
                            if(webProductIdAndNumMap.containsKey(id)){
                                productNum = Arith.add(productNum, webProductIdAndNumMap.get(id));
                                productIdAndNumMap.put(id, productNum);
                            } else {
                                webMap.putAll(webProductIdAndNumMap);
                            }
                        }
                        if(!webMap.isEmpty()){
                            productIdAndNumMap.putAll(webMap);
                        }
                    }
                } else if(isNew && webProductIdAndNumMap.isEmpty() && !sumSelf){
                    // 当新建时，退款数据还没有入库，这个时候直接塞值(新建只有一条数据)
                    Iterator allEntries = allContractCostMap.entrySet().iterator();
                    while(allEntries.hasNext()){
                        Map.Entry allEntry = (Map.Entry) allEntries.next();
                        Long id = (Long) allEntry.getKey();
                        Double amount = allContractCostMap.get(id);
                        amount = Arith.add(amount, returnAmount);
                        allContractCostMap.put(contractId, amount);
                    }
                }

                //判断是否是新旧数据
                boolean sourceDoc = false;
                for(ContractProductEntity entity : contractProductEntityList){
                    JSONObject data = entity.getData();
                    if (data.containsKey(SelectProductEnum.SOURCE_DOC.getAttr())) {
                        sourceDoc = true;
                        break;
                    }
                }
                // 新数据直接使用累加结果
                if(sourceDoc){
                    contractIdAndCostMap.put(key, jxc2UpdateInstockCost);
                    break;
                }

                //-----------------------旧数据处理---------------------------
                List<Long> outstockIdList = allContractOutMap.get(key);
                if(outstockIdList != null && instockList != null && isOpenJxc){
                    Map<String,Object> outstockParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    outstockParam.put("corpid", corpid);
                    outstockParam.put("del", DelEnum.NORMAL.getDel());
                    outstockParam.put("outstockIdIn", outstockIdList);
                    List<OutstockProductEntity> outstockProductList = outstockProductModel.findEntitys(outstockParam);
                    Map<Long, OutstockProductEntity> outstockProductEntityMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    // 算出每个产品对应的成本
                    Map<Long, Double> productIdAndCost = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    // 所有的出库记录
                    for (OutstockProductEntity outstockProductEntity : outstockProductList) {
                        Long productId = outstockProductEntity.getProductId();
                        Double productNum = outstockProductEntity.getProductNum() == null ? 0D : outstockProductEntity.getProductNum();
                        Double productCost = outstockProductEntity.getCost() == null ? 0D : outstockProductEntity.getCost();
                        // 将所有记录的相同产品的平均成本求出
                        if (outstockProductEntityMap.containsKey(productId)) {
                            OutstockProductEntity oldOutstockProductEntity = outstockProductEntityMap.get(productId);
                            Double oldProductNum = oldOutstockProductEntity.getProductNum() == null ? 0D : oldOutstockProductEntity.getProductNum();
                            Double oldProductCost = oldOutstockProductEntity.getCost() == null ? 0D : oldOutstockProductEntity.getCost();
                            // 上一次的产品总成本
                            Double oldCost = Arith.mul(oldProductNum, oldProductCost);
                            // 这一次的产品总成本
                            Double newCost = Arith.mul(productNum, productCost);
                            // (上一次的产品总成本+这一次的产品总成本)/两次的总数量
                            productCost = Arith.div(Arith.add(oldCost, newCost), Arith.add(oldProductNum, productNum), 2);
                        }
                        outstockProductEntityMap.put(productId, outstockProductEntity);
                        productIdAndCost.put(productId, productCost);
                    }

                    // 遍历入库产品
                    Iterator iterator = instockProductIdAndNum.keySet().iterator();
                    while (iterator.hasNext()) {
                        Long id = Long.valueOf(iterator.next().toString());
                        Double productNum = instockProductIdAndNum.get(id);
                        if(productIdAndCost.containsKey(id)){
                            costAmount = Arith.add(costAmount, Arith.mul(productNum, productIdAndCost.get(id)));
                        }
                    }
                } else if(!isOpenJxc){
                    // 不开启进销存是直接查询原合同关联产品表的成本*红冲合同产品表的产品数量(退货产品数量)
                    BoolQueryBuilder boolQueryBuilder = boolQuery();
                    boolQueryBuilder.filter(termQuery("corpid.keyword",corpid));
                    boolQueryBuilder.filter(termQuery(StringConstant.DEL,DelEnum.NORMAL.getDel()));
                    boolQueryBuilder.filter(termQuery(ContractProductSubFormEnum.getEsAttr(ContractProductSubFormEnum.TYPE), 201));
                    boolQueryBuilder.filter(termQuery(ContractProductSubFormEnum.getEsAttr(ContractProductSubFormEnum.CONTRACT_ID),key));
                    boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, IndexTypeEnum.IDX_SAAS_CONTRACT_PRODUCT.getType()));
                    List<String> fieldList = Arrays.asList(ContractProductSubFormEnum.getAttrConnectData(ContractProductSubFormEnum.PRODUCT_ID), ContractProductSubFormEnum.getAttrConnectData(ContractProductSubFormEnum.CONTRACT_ID), ContractProductSubFormEnum.getAttrConnectData(ContractProductSubFormEnum.PRODUCT_NUM), ContractProductSubFormEnum.getAttrConnectData(ContractProductSubFormEnum.PRICE), ContractProductSubFormEnum.getAttrConnectData(ContractProductSubFormEnum.COST));
                    List<PaasFormDataEntity> list =  esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_CONTRACT_PRODUCT,boolQueryBuilder, PaasFormDataEntity.class, fieldList);
                    if(list.size() > 0) {
                        List<ContractProductEntity> contractProductEntities = transferSubFormHelper.transferFormDataToContractProductList(list);
                        for (ContractProductEntity contractProductEntity : contractProductEntities) {
                            Long productId = contractProductEntity.getProductId();
                            Double cost = contractProductEntity.getCost() == null ? 0D : contractProductEntity.getCost();
                            if(productIdAndNumMap.containsKey(productId)){
                                Double productCost = Arith.mul(cost, productIdAndNumMap.get(productId));
                                costAmount = Arith.add(costAmount, productCost);
                            }
                        }
                    }
                }
            }
            contractIdAndCostMap.put(key, costAmount);
        }

        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
        boolQueryBuilder.filter(termQuery("del", 0));
        boolQueryBuilder.filter(termQuery("data." + OutstockEnum.TYPE.getAttr(), OutstockTypeEnum.CONTRACT_OUTSTOCK.getCode()));
        boolQueryBuilder.filter(termsQuery("data." + OutstockEnum.REF_ID.getAttr(), Arrays.asList(contractId)));
        boolQueryBuilder.filter(termsQuery("flowStatus", Arrays.asList(FlowStatusEnum.NOT_NEED_APPROVAL.getType(), FlowStatusEnum.PASS.getType())));
        boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, IndexTypeEnum.IDX_SAAS_OUTSTOCK.getType()));
        List<PaasFormDataEntityExt> outstockList = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_OUTSTOCK, boolQueryBuilder, PaasFormDataEntityExt.class, Arrays.asList(OutstockEnum.getAttrConnectData(OutstockEnum.REF_ID), FieldTypeEnum.DATAID.getAlias()));

        // 根据出库单获取对应的产品
        List<Long> dataIdIn = new ArrayList<>();
        outstockList.forEach(outstock -> dataIdIn.add(outstock.getDataId()));
        Map<String, Object> outstockParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        outstockParam.put("corpid", corpid);
        outstockParam.put("del", 0);
        outstockParam.put("outstockIdIn", dataIdIn);
        List<OutstockProductEntity> outstockAllProductList = outstockProductModel.findEntitys(outstockParam);

        // 合同和关联的出库单的对应关系
        Map<Long, List<Long>> contractOutstockMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        List<Long> outstockIdList = contractOutstockMap.get(contractId);
        if (outstockIdList == null) {
            outstockIdList = new ArrayList<>();
        }
        for (PaasFormDataEntityExt outstock : outstockList) {
            Long refId = outstock.getData().getLong(OutstockEnum.REF_ID.getAttr());
            if (Objects.equals(contractId, refId)) {
                outstockIdList.add(outstock.getDataId());
            }
        }
        contractOutstockMap.put(contractId, outstockIdList);

        // 合同和出库产品的对应关系
        Map<Long, List<OutstockProductEntity>> contractOutstockProductMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        List<Long> outstockIdLists = contractOutstockMap.get(contractId);
        List<OutstockProductEntity> outstockProductEntityList = contractOutstockProductMap.get(contractId);
        if (outstockProductEntityList == null) {
            outstockProductEntityList = new ArrayList<>();
        }
        for (OutstockProductEntity outstockProductEntity : outstockAllProductList) {
            Long outstockId = outstockProductEntity.getOutWarehouseId();
            if (outstockIdLists.contains(outstockId)) {
                outstockProductEntityList.add(outstockProductEntity);
            }
        }
        contractOutstockProductMap.put(contractId, outstockProductEntityList);

        // 合同和关联产品的对应关系
        List<ContractProductEntity> contractProList = contractProductModel.getContractProductByContractIdIn(corpid, Arrays.asList(contractId));
        Map<Long, List<ContractProductEntity>> contractProductMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        List<ContractProductEntity> contractProductEntityList = contractProductMap.get(contractId);
        if (contractProductEntityList == null) {
            contractProductEntityList = new ArrayList<>();
        }
        for (ContractProductEntity contractProductEntity : contractProList) {
            if (Objects.equals(contractProductEntity.getContractId(), contractId)) {
                contractProductEntityList.add(contractProductEntity);
            }
        }
        contractProductMap.put(contractId, contractProductEntityList);

        // 整理数据
        List<OutstockProductEntity> outstockProductList = contractOutstockProductMap.get(contractId);
        List<ContractProductEntity> contractProductList = contractProductMap.get(contractId);

        // 计算合同出库成本：SUM（已出库产品数量*出库产品成本）
        double realCost = 0D;
        boolean isOld = false;
        // 合并的出库产品数量MAP
        Map<Long, Double> outstockProductNumMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        // 行对应数量
        Map<Long, Double> lineProductNumMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (OutstockProductEntity outstockProductEntity : outstockProductList) {
            if (Objects.isNull(outstockProductEntity.getRefProductId())) {
                isOld = true;
            }
            Long productId = outstockProductEntity.getProductId();
            Double productNum = outstockProductEntity.getProductNum();
            productNum = productNum == null ? 0D : productNum;
            Double cost = outstockProductEntity.getCost();
            cost = cost == null ? 0D : cost;
            realCost = Arith.add(realCost, Arith.mul(productNum, cost));
            if (outstockProductNumMap.containsKey(productId)) {
                outstockProductNumMap.put(productId, Arith.add(outstockProductNumMap.get(productId), productNum));
            } else {
                outstockProductNumMap.put(productId, productNum);
            }
            if (!isOld) {
                Long refProductId = outstockProductEntity.getRefProductId();
                if (lineProductNumMap.containsKey(refProductId)) {
                    lineProductNumMap.put(refProductId, Arith.add(lineProductNumMap.get(refProductId), productNum));
                } else {
                    lineProductNumMap.put(refProductId, productNum);
                }
            }
        }

        // 算出合同中每种产品的平均价
        Map<Long, String> avgCostMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (ContractProductEntity contractProductEntity : contractProductList) {
            Long productId = contractProductEntity.getProductId();
            Double productNum = contractProductEntity.getProductNum() == null ? 0D : Math.abs(contractProductEntity.getProductNum());
            if (isOld) {
                if (avgCostMap.containsKey(productId)) {
                    // map中已经有相同产品，需要计算平均值
                    String productInfo = avgCostMap.get(productId);
                    String[] split = productInfo.split(",");
                    Double preCost = StringUtil.toDouble((split[0]), 0D);
                    Double preNum = StringUtil.toDouble((split[1]), 0D);
                    Double nowCost = SaasProductHelp.calculateCost(preNum, preCost, productNum, contractProductEntity.getCost(), 1);
                    Double nowNum = Arith.add(preNum, productNum);
                    avgCostMap.put(productId, nowCost + "," + nowNum);
                } else {
                    // 将产品id为key，合同产品平均价和数量拼接字符串为value存入map中
                    String productInfo = contractProductEntity.getCost() + "," + productNum;
                    avgCostMap.put(productId, productInfo);
                }
            } else if (lineProductNumMap.containsKey(contractProductEntity.getId())) {
                // 分行已出库数量计算
                contractProductEntity.setContractOutstockNum(lineProductNumMap.get(contractProductEntity.getId()));
            }
        }
        double estimateCost = 0D;
        if (isOld) {
            // 老数据合同预估成本计算
            for (ContractProductEntity contractProductEntity : contractProductList) {
                String productInfo = avgCostMap.get(contractProductEntity.getProductId());
                if (org.apache.commons.lang.StringUtils.isEmpty(productInfo)) {
                    continue;
                }
                String[] productInfos = productInfo.split(",");
                if (outstockProductNumMap.containsKey(contractProductEntity.getProductId())) {
                    if (Arith.sub(contractProductEntity.getProductNum(), outstockProductNumMap.get(contractProductEntity.getProductId())) > 0) {
                        estimateCost = Arith.add(estimateCost, Arith.mul(Arith.sub(contractProductEntity.getProductNum(), outstockProductNumMap.get(contractProductEntity.getProductId())), StringUtil.toDouble((productInfos[0]), 0D)));
                    }
                } else {
                    estimateCost = Arith.add(estimateCost, Arith.mul(contractProductEntity.getProductNum(), StringUtil.toDouble((productInfos[0]), 0D)));
                }
            }
        } else {
            // 新数据合同预估成本计算
            for (ContractProductEntity contractProductEntity : contractProductList) {
                if (Arith.sub(contractProductEntity.getProductNum(), contractProductEntity.getContractOutstockNum()) > 0) {
                    estimateCost = Arith.add(estimateCost, Arith.mul(contractProductEntity.getCost(), Arith.sub(contractProductEntity.getProductNum(), contractProductEntity.getContractOutstockNum())));
                }
            }
        }

        // 合同成本 = 合同产品成本 - 退货产品成本（入库单的产品成本：新数据用入库单的成本，旧数据用出库单的平均成本）+ 其他费用
        Double surchargeAmount = FastJsonHelper.getDoubleOrDefaultFromFormData(contractData, ContractEnum.OTHER_EXPENSE.getAttr(), BasicConstant.ZERO_DOUBLE);
        Double contractCost;
        if(contractIdAndCostMap.containsKey(contractId)){
            Double cost = contractIdAndCostMap.get(contractId) == null ? BasicConstant.ZERO_DOUBLE : contractIdAndCostMap.get(contractId);
            contractCost = Arith.sub(Arith.add(Arith.add(estimateCost, realCost), surchargeAmount), cost);
        } else {
            contractCost = Arith.add(Arith.add(estimateCost, realCost), surchargeAmount);
        }
        updateContractData.put(ContractEnum.CONTRACT_COST.getAttr(), Arith.round(contractCost, 2));

        //合同毛利 = 合同金额 - 退货金额（关联计算）- 合同成本（同上）
        Double amount = FastJsonHelper.getDoubleOrDefaultFromFormData(contractData, ContractEnum.AMOUNT.getAttr(), 0D);
        Double grossProfit;
        if(allContractCostMap.containsKey(contractId)){
            Double cost = allContractCostMap.get(contractId) == null ? BasicConstant.ZERO_DOUBLE : allContractCostMap.get(contractId);
            grossProfit = Arith.sub(Arith.sub(amount, contractCost), cost);
        } else {
            grossProfit = Arith.sub(amount, contractCost);
        }
        updateContractData.put(ContractEnum.GROSS_PROFIT.getAttr(), Arith.round(grossProfit, 2));

        // 合同毛利率
        if (Double.compare(amount, BasicConstant.ZERO_DOUBLE) != 0) {
            updateContractData.put(ContractEnum.GROSS_PROFIT_RATE.getAttr(), Arith.round(Arith.div(grossProfit, amount), 4));
        } else {
            updateContractData.put(ContractEnum.GROSS_PROFIT_RATE.getAttr(), BasicConstant.ZERO_DOUBLE);
        }

        // 现金毛利 = 合同已收款金额 - 合同成本（同上）
        Double finishAmount = FastJsonHelper.getDoubleOrDefaultFromFormData(contractData, ContractEnum.FINISH_AMOUNT.getAttr(), 0D);
        Double cashProfit = Arith.sub(finishAmount, contractCost);
        updateContractData.put(ContractEnum.CASH_PROFIT.getAttr(), cashProfit);
        // 现金毛利率
        if (Double.compare(finishAmount, BasicConstant.ZERO_DOUBLE) != 0) {
            updateContractData.put(ContractEnum.CASH_PROFIT_RATE.getAttr(), Arith.round(Arith.div(cashProfit, finishAmount), 2));
        } else {
            updateContractData.put(ContractEnum.CASH_PROFIT_RATE.getAttr(), BasicConstant.ZERO_DOUBLE);
        }
        UpdateDataEntity updateData = ExplainUtil.getUpdateData(contractEntityExt.getId(), updateContractData, corpid);
        contractModel.updateBatch(Collections.singletonList(updateData), corpid);
    }


    /**
     * 生成红冲回款单
     *
     * @param redContractEntity 红冲合同实体
     * @param paymentSheetArray 选择关联的回款单
     * @param saasFormSaveDTO   保存入参
     * @throws XbbException 异常
     */
    public List<Long> generateRedPayment(ContractEntityExt redContractEntity, JSONArray paymentSheetArray, SaasFormSaveDTO saasFormSaveDTO) throws XbbException {
        List<Long> redPaymentSheetIds = new ArrayList<>();
        JSONObject newData = saasFormSaveDTO.getNewData();
        if (redContractEntity == null || newData == null) {
            return redPaymentSheetIds;
        }
        if (paymentSheetArray == null || paymentSheetArray.isEmpty()) {
            return redPaymentSheetIds;
        }
        //是否设置红冲回款单的id,老审批应该为true,工作流公司回款单如果开了工作流审批 应该为false,其他情况均为true
        boolean isSetPaymentFlag = true;
        String corpid = saasFormSaveDTO.getCorpid();
        if (commonHelp.isOpenWorkFlow(corpid)) {
            Map<String, Object> params = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            params.put("del", 0);
            params.put("businessType", XbbRefTypeEnum.PAYMENT_SHEET.getCode());
            params.put("corpid", corpid);
            List<PaasFormEntityExt> paasFormEntityExts = paasFormModel.findEntitys(params);
            Long paymentSheetFormId = CollectionsUtil.isNotEmpty(paasFormEntityExts) ? paasFormEntityExts.get(BasicConstant.ZERO).getId() : 0L;
            List<WorkflowEntity> list = workflowFormDataOperationService.getSatisfyTriggerEntitys(corpid,
                    paymentSheetFormId, XbbRefTypeEnum.PAYMENT_SHEET.getCode(), Arrays.asList(TriggerEventTypeEnum.ONLY_ADD.getType(), TriggerEventTypeEnum.ADD_OR_UPDATE.getType()));
            isSetPaymentFlag = !(CollectionsUtil.isNotEmpty(list) && list.stream().map(WorkflowEntity::getEnable).collect(Collectors.toList()).contains(BasicConstant.ONE));
        }
        // 退货退款关联的回款单
        for(Object obj : paymentSheetArray) {
            JSONObject paymentJsonObject = (JSONObject) obj;
            String refundCreatorId = saasFormSaveDTO.getNewPaasFormDataEntity().getCreatorId();
            if (refundCreatorId != null) {
                paymentJsonObject.put(StringConstant.CREATOR_ID, refundCreatorId);
            }
            PaasFormDataEntityExt paymentSheetEntityExt;
            paymentSheetEntityExt = handlePaymentSheetWebPlatformLinkAddData(paymentJsonObject);
            FormDataAddDTO formDataAddDTO = new FormDataAddDTO();
            BeanUtil.copyProperties(paymentSheetEntityExt, formDataAddDTO);
            BeanUtil.copyProperties(saasFormSaveDTO, formDataAddDTO);
            JSONObject dataList = paymentSheetEntityExt.getData();
            dataList.remove(PaymentSheetEnum.INVOICE_AMOUNT.getAttr());
            JSONObject paymentSheetTypeObj = FastJsonHelper.getJsonObjectOrDefaultFromFormData(dataList, PaymentSheetEnum.PAYMENT_SHEET_TYPE.getAttr(), new JSONObject());
            PaymentSheetTypeEnum paymentSheetTypeEnum = PaymentSheetTypeEnum.getByCode(paymentSheetTypeObj.getString("value"));
            JSONArray amountDetail = dataList.getJSONArray(PaasConstant.AMOUNTDETAIL);
            //金额中处理回款单类型从数组格式修正为数字形式
            if (amountDetail != null ) {
                amountDetail.forEach(e -> {
                    JSONObject jsonObject = (JSONObject) e;
                    if(jsonObject.get(PaymentSheetEnum.PAYMENT_SHEET_TYPE.getAttr()) instanceof JSONObject){
                        JSONObject sonTypeObj = jsonObject.getJSONObject(PaymentSheetEnum.PAYMENT_SHEET_TYPE.getAttr());
                        if(sonTypeObj != null && sonTypeObj.getString("value") != null){
                            jsonObject.put(PaymentSheetEnum.PAYMENT_SHEET_TYPE.getAttr(), sonTypeObj.getString("value"));
                        }
                    }
                });
            }
            if (Objects.equals(paymentSheetTypeEnum, PaymentSheetTypeEnum.WRITE_OFF)) {
                dataList.put(PaymentSheetEnum.PAYMENT_SHEET_TYPE.getAttr(), PaymentSheetTypeEnum.RED_WRITE_OFF.getCode());
                formDataAddDTO.setBusinessType(XbbRefTypeEnum.RED_PAYMENT_SHEET.getCode());
                formDataAddDTO.setSubBusinessType(XbbRefTypeEnum.RED_PAYMENT_SHEET.getCode());
            } else if (Objects.equals(paymentSheetTypeEnum, PaymentSheetTypeEnum.WRITE_OFF_PREPAYMENT)) {
                if (Objects.equals(saasFormSaveDTO.getDistributorMark(), DistributorMarkEnum.DISTRIBUTOR.getCode())) {
                    dataList.put(PaymentSheetEnum.PAYMENT_SHEET_TYPE.getAttr(), PaymentSheetTypeEnum.RED_WRITE_OFF_BALANCE.getCode());
                    formDataAddDTO.setBusinessType(XbbRefTypeEnum.RED_WRITE_OFF_BALANCE.getCode());
                    formDataAddDTO.setSubBusinessType(XbbRefTypeEnum.RED_WRITE_OFF_BALANCE.getCode());
                } else {
                    dataList.put(PaymentSheetEnum.PAYMENT_SHEET_TYPE.getAttr(), PaymentSheetTypeEnum.RED_WRITE_OFF_PREPAYMENT.getCode());
                    formDataAddDTO.setBusinessType(XbbRefTypeEnum.RED_WRITE_OFF_PREPAYMENT.getCode());
                    formDataAddDTO.setSubBusinessType(XbbRefTypeEnum.RED_WRITE_OFF_PREPAYMENT.getCode());
                }
            } else {
                throw new XbbException(BusinessTypeErrorCodeEnum.API_ERROR_361001);
            }
            formDataAddDTO.setDataList(dataList);
            formDataAddDTO.setSaasMark(SaasMarkEnum.SAAS.getCode());
            SaasNeedRedundantAttrPojo saasNeedRedundantAttrPojo = new SaasNeedRedundantAttrPojo();
            saasNeedRedundantAttrPojo.setRefundId(saasFormSaveDTO.getNewPaasFormDataEntity().getId());
            formDataAddDTO.setSaasNeedRedundantAttrPoJo(saasNeedRedundantAttrPojo);
            JSONArray ownerJsonArray = paymentJsonObject.getJSONArray(FieldTypeEnum.OWNERID.getAlias());
            JSONArray coUserJsonArray = paymentJsonObject.getJSONArray(FieldTypeEnum.COUSERID.getAlias());
            List<ReturnUserAndDepartmentPojo> ownerId = new ArrayList<>();
            List<ReturnUserAndDepartmentPojo> coUserId = new ArrayList<>();
            if (Objects.nonNull(ownerJsonArray) && ownerJsonArray.size() > BasicConstant.ZERO) {
                ownerId = JSONArray.parseArray(ownerJsonArray.toJSONString(), ReturnUserAndDepartmentPojo.class);
            }
            if (Objects.nonNull(coUserJsonArray) && coUserJsonArray.size() > BasicConstant.ZERO) {
                coUserId = JSONArray.parseArray(coUserJsonArray.toJSONString(), ReturnUserAndDepartmentPojo.class);
            }
            formDataAddDTO.setOwnerId(ownerId);
            formDataAddDTO.setCoUserId(coUserId);
            formDataAddDTO.setPlatform(PlatFormEnum.INTERNAL.getValue());
            FormDataAddVO formDataAddVO = workflowOperatorDataService.add(formDataAddDTO);
            if (formDataAddVO.getDataId() != null && isSetPaymentFlag) {
                redPaymentSheetIds.add(formDataAddVO.getDataId());
            }
        }
        return redPaymentSheetIds;
    }

    /**
     * 处理web端关联新建红冲回款单数据组装
     * @param paymentJsonObject web端返回新建回款单信息
     * @return 回款单实体
     * @author zhouwq
     * @date 2019/12/6 15:17
     */
    private PaasFormDataEntityExt handlePaymentSheetWebPlatformLinkAddData(JSONObject paymentJsonObject){
        PaasFormDataEntityExt entityExt = new PaasFormDataEntityExt();
        if (paymentJsonObject == null) {
            return entityExt;
        }
        entityExt.setSerialNo(paymentJsonObject.getString(PaymentSheetEnum.SHEET_NO.getAttr()));
        entityExt.setId(paymentJsonObject.getLong(StringConstant.SAAS_LINK_BUSINESS_ID));
        entityExt.setDataId(paymentJsonObject.getLong(StringConstant.DATA_ID));
        entityExt.setFormId(paymentJsonObject.getLong("formId"));
        entityExt.setMenuId(paymentJsonObject.getLong("menuId"));
        entityExt.setAppId(paymentJsonObject.getLong("appId"));
        entityExt.setAlone(paymentJsonObject.getInteger(FieldTypeEnum.SHEET_ALONE.getAlias()));
        entityExt.setUuid(paymentJsonObject.getString(FieldTypeEnum.SHEET_UUID.getAlias()));
        entityExt.setAddTime(paymentJsonObject.getLong("addTime"));
        entityExt.setUpdateTime(paymentJsonObject.getLong("updateTime"));
        entityExt.setOwnerId(paymentJsonObject.getString("ownerId"));
        entityExt.setFlowStatus(paymentJsonObject.getInteger("flowStatus"));
        entityExt.setDepartmentId(0L);
        entityExt.setDel(paymentJsonObject.getInteger("del"));
        entityExt.setCreatorId(paymentJsonObject.getString(StringConstant.CREATOR_ID));
        paymentJsonObject.remove("addTime");
        paymentJsonObject.remove("updateTime");
        paymentJsonObject.remove(PaymentSheetEnum.SHEET_NO.getAttr());
        entityExt.setData(paymentJsonObject);
        return entityExt;
    }



    public List<Long> saveRefundInvoice(SaasFormSaveDTO saasFormSaveDTO, JSONArray invoiceArray, Long redContractId, Integer flowStatus) throws XbbException {
        Long now = DateTimeUtil.getInt();
        PaasFormDataEntity newPaasFormDataEntity = saasFormSaveDTO.getNewPaasFormDataEntity();
        String corpid = saasFormSaveDTO.getCorpid();
        Long refundId = newPaasFormDataEntity.getId();
        List<Long> invoiceIds = new ArrayList<>();
        if (Objects.isNull(redContractId) || Objects.isNull(invoiceArray)) {
            return invoiceIds;
        }
        //关联作废/红冲发票处理
        List<Long> cancelInvoiceIds = new ArrayList<>();
        for(Object obj : invoiceArray){
            JSONObject invoiceJsonObject = (JSONObject)obj;
            String refundCreatorId = saasFormSaveDTO.getNewPaasFormDataEntity().getCreatorId();
            if (refundCreatorId != null) {
                invoiceJsonObject.put(StringConstant.CREATOR_ID, refundCreatorId);
            }
            PaasFormDataEntity invoiceEntity = handleInvoiceWebPlatformLinkAddData(invoiceJsonObject);
            JSONObject invoiceData = invoiceEntity.getData();
            Integer isCancel = invoiceData.getInteger(InvoiceEnum.IS_CANCEL.getAttr());
            Integer isRed = invoiceData.getInteger(InvoiceEnum.IS_RED.getAttr());
            Long invoiceId = invoiceEntity.getId();
            if(Objects.equals(IsCancelEnum.IS_CANCEL.getCode(), isCancel)){
                cancelInvoiceIds.add(invoiceEntity.getId());
            }
            if(Objects.equals(IsRedEnum.RED.getCode(), isRed)){
                //关联红冲发票新建
                FormDataAddDTO formDataAddDTO = new FormDataAddDTO();
                BeanUtil.copyProperties(invoiceEntity, formDataAddDTO);
                BeanUtil.copyProperties(saasFormSaveDTO, formDataAddDTO);
                JSONObject data = invoiceEntity.getData();
                // com.xbongbong.saas.service.impl.RefundServiceImpl.invoiceAmountDetailHandle 是个空方法
//                invoiceAmountDetailHandle(data);
                formDataAddDTO.setDataList(data);
                formDataAddDTO.setBusinessType(XbbRefTypeEnum.INVOICE.getCode());
                formDataAddDTO.setSubBusinessType(XbbRefTypeEnum.INVOICE.getCode());
                formDataAddDTO.setSaasMark(SaasMarkEnum.SAAS.getCode());
                SaasNeedRedundantAttrPojo saasNeedRedundantAttrPojo = new SaasNeedRedundantAttrPojo();
                saasNeedRedundantAttrPojo.setRefundId(saasFormSaveDTO.getNewPaasFormDataEntity().getId());
                formDataAddDTO.setSaasNeedRedundantAttrPoJo(saasNeedRedundantAttrPojo);
                formDataAddDTO.setPlatform(PlatFormEnum.INTERNAL.getValue());
                FormDataAddVO formDataAddVO = workflowOperatorDataService.add(formDataAddDTO);

                // 发票如果开启流程，返回的发票为空
                invoiceId = formDataAddVO.getDataId();
            }
            if (invoiceId != null) {
                RefundInvoiceEntity refundInvoiceEntity = new RefundInvoiceEntity();
                refundInvoiceEntity.setRefundId(refundId);
                refundInvoiceEntity.setCorpid(corpid);
                refundInvoiceEntity.setDel(DelEnum.NORMAL.getDel());
                refundInvoiceEntity.setAddTime(now);
                refundInvoiceEntity.setUpdateTime(now);
                refundInvoiceEntity.setInvoiceId(invoiceId);
                refundInvoiceEntity.setRedContractId(redContractId);
                refundInvoiceEntity.setRedPaymentId(0L);
                refundInvoiceEntity.setFlowStatus(flowStatus);
                refundInvoiceModel.save(refundInvoiceEntity);
                invoiceIds.add(invoiceId);
            }
        }
        // 关联作废发票
        if (!cancelInvoiceIds.isEmpty()) {
            CancelDTO cancelDTO = new CancelDTO();
            BeanUtil.copyProperties(saasFormSaveDTO, cancelDTO);
            cancelDTO.setSingle(0);
            cancelDTO.setStatus(1);
            cancelDTO.setBusinessType(XbbRefTypeEnum.INVOICE.getCode());
            cancelDTO.setDataIdList(cancelInvoiceIds);
            cancelDTO.setPlatform(PlatFormEnum.INTERNAL.getValue());
            listBatchService.cancel(cancelDTO);
        }
        return invoiceIds;
    }


    /**
     * 处理web端关联新建发票数据组装
     * @param paymentJsonObject web端返回新建回款单信息
     * @return 回款单实体
     * @author zhouwq
     * @date 2019/12/6 15:17
     */
    private PaasFormDataEntity handleInvoiceWebPlatformLinkAddData(JSONObject paymentJsonObject){
        PaasFormDataEntity paasFormDataEntity = new PaymentSheetEntityExt();
        paasFormDataEntity.setSerialNo(paymentJsonObject.getString(PaymentSheetEnum.SHEET_NO.getAttr()));
        paasFormDataEntity.setId(paymentJsonObject.getLong(StringConstant.SAAS_LINK_BUSINESS_ID));
        paasFormDataEntity.setDataId(paymentJsonObject.getLong(StringConstant.DATA_ID));
        paasFormDataEntity.setFormId(paymentJsonObject.getLong("formId"));
        paasFormDataEntity.setMenuId(paymentJsonObject.getLong("menuId"));
        paasFormDataEntity.setAppId(paymentJsonObject.getLong("appId"));
        paasFormDataEntity.setAddTime(paymentJsonObject.getLong("addTime"));
        paasFormDataEntity.setUpdateTime(paymentJsonObject.getLong("updateTime"));
        paasFormDataEntity.setOwnerId(paymentJsonObject.getString("ownerId"));
        paasFormDataEntity.setFlowStatus(paymentJsonObject.getInteger("flowStatus"));
        paasFormDataEntity.setDepartmentId(0L);
        paasFormDataEntity.setDel(paymentJsonObject.getInteger("del"));
        paasFormDataEntity.setCreatorId(paymentJsonObject.getString("creatorId"));
        paymentJsonObject.remove("addTime");
        paymentJsonObject.remove("updateTime");
        paymentJsonObject.remove(PaymentSheetEnum.SHEET_NO.getAttr());
        paasFormDataEntity.setData(paymentJsonObject);
        return paasFormDataEntity;
    }

    /**
     * 更新退货单产品
     *
     * @param newRefundEntityExt     前端传入的数据
     * @author youli.chen
     * @date  2019/2/21 22:01
     */
    public Map<Long, Double> setRefundProducts(RefundEntityExt newRefundEntityExt) throws XbbException {
        String corpid = newRefundEntityExt.getCorpid();
        JSONObject refundData = newRefundEntityExt.getData();

        Long redContractId = FastJsonHelper.getLongOrDefaultFromFormData(refundData, RefundEnum.RED_CONTRACT_ID.getAttr(), 0L);
        JSONArray productArray = refundData.getJSONArray(RefundEnum.PRODUCTS.getAttr());

        Map<String, Object> modelMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        modelMap.put("corpid", corpid);
        modelMap.put("contractId", redContractId);
        modelMap.put("del", DelEnum.NORMAL.getDel());
        List<ContractProductEntity> contractProductEntityList = contractProductModel.findEntitys(modelMap);
        Map<Long, ContractProductEntity> orginProductMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);

        contractProductEntityList.forEach(item -> orginProductMap.put(item.getId(), item));
        Map<Long, ContractProductEntity> orginProductMapCopy = new HashMap<>(orginProductMap);
        List<ContractProductEntity> productAddList = new ArrayList<>();
        List<ContractProductEntity> productUpdateList = new ArrayList<>();
        Map<Long, PaasFormDataEntityExt> productMap = saasProductHelp.product2saveMap(corpid,productArray);
        Integer sort = 0;
        Map<Long, Double> changeNumMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);

        for (int i = 0; i < productArray.size(); i++) {
            JSONObject jsonObject = productArray.getJSONObject(i);
            Long pageProductId = jsonObject.getLong(SelectProductEnum.PRODUCT.getAttr());
            Long businessProductId = jsonObject.getLong(BusinessConstant.PRODUCT_SUB_ID);
            sort++;
            Double productNum = jsonObject.getDouble(ContractProductEnum.NUM.getAttr());
            boolean addProductFlag = businessProductId == null || businessProductId.equals(0L) || businessProductId < 0L;
            ContractProductEntity contractProductEntity;
            Double originNum = 0D;
            if (addProductFlag) {
                //新增产品
                contractProductEntity = new ContractProductEntity();
                productAddList.add(contractProductEntity);
            } else if (orginProductMap.containsKey(businessProductId)) {
                //编辑产品
                contractProductEntity = orginProductMap.get(businessProductId);
                productUpdateList.add(contractProductEntity);
                originNum = Math.abs(contractProductEntity.getProductNum());
                //只剩删除的产品
                orginProductMap.remove(businessProductId);
            } else {
                //删除产品
                continue;
            }
            JSONObject productData = productMap.get(pageProductId).getData();
            contractProductEntity.setCorpid(corpid);
            contractProductEntity.setContractId(redContractId);
            contractProductEntity.setParentId(productData.getLong(ProductEnum.PARENT_ID.getAttr()));
            contractProductEntity.setProductId(pageProductId);
            contractProductEntity.setProductNum(-productNum);
            contractProductEntity.setProductName(productData.getString(ProductEnum.NAME.getAttr()));
            contractProductEntity.setProductNo(productData.getString(ProductEnum.PRODUCT_NO.getAttr()));
            Double price = jsonObject.getDouble(RefundProductEnum.PRICE.getAttr());
            price = price != null ? price : 0D;
            contractProductEntity.setPrice(price);
            Integer enableMultiUnit = productData.getInteger(ProductEnum.ENABLE_MULTI_UNIT.getAttr());
            if (Objects.equals(enableMultiUnit, 1)) {
                ProductUtil.setBusinessUnit(jsonObject, contractProductEntity);
                contractProductEntity.setProductUnit(jsonObject.getString(SelectProductEnum.UNIT.getAttr()));
            } else {
                contractProductEntity.setProductUnit(productData.getString(ProductEnum.UNIT.getAttr()));
                jsonObject.put(SelectProductEnum.UNIT.getAttr(),productData.getString(ProductEnum.UNIT.getAttr()));
            }
            // contractProductEntity.setProductUnit(productData.getString(ProductEnum.UNIT.getAttr()));
            // 折扣：默认为100%
            Double discount = jsonObject.getDouble(ContractProductEnum.DISCOUNT.getAttr());
            discount = discount == null ? 100 : discount;
            contractProductEntity.setDiscount(discount);
            contractProductEntity.setSpecification(productData.getString(ProductEnum.SPECIFICATION_LINK_TEXT.getAttr()));
            contractProductEntity.setContractOutstockNum(0D);
            contractProductEntity.setInstockNum(0D);
            // 备注
            String memo = jsonObject.getString(ContractProductEnum.MEMO.getAttr());
            contractProductEntity.setMemo(memo);
            contractProductEntity.setBarcode(productData.getString(ProductEnum.BARCODE.getAttr()));
            contractProductEntity.setCost(jsonObject.getDouble(SelectProductEnum.COST.getAttr()));
            contractProductEntity.setHistoricalPrice(productData.getDouble(ProductEnum.PRICE.getAttr()));
            contractProductEntity.setSort(sort);
            JSONArray imgArr = FastJsonHelper.getJsonArrFromFormData(productData, ProductEnum.PRODUCT_IMGS.getAttr());
            if (Objects.isNull(imgArr) || imgArr.isEmpty()) {
                imgArr = FastJsonHelper.getJsonArrFromFormData(productData, ProductEnum.THUMBNAIL.getAttr());
            } else {
                imgArr = JSONArray.parseArray(JSON.toJSONString(imgArr.subList(0, 1)));
            }
            contractProductEntity.setProductThumbnail(imgArr.toJSONString());
            contractProductEntity.setType(ContractProductTypeEnum.REFUND.getCode());
            jsonObject.put(ContractProductEnum.UNIT.getAttr(),productData.getString(ProductEnum.UNIT.getAttr()));
            contractProductEntity.setData(jsonObject);
            if (Objects.nonNull(jsonObject.getLong(BusinessConstant.PRODUCT_SUB_ID))) {
//                contractProductEntity.setRefProductId(jsonObject.getLong(BusinessConstant.PRODUCT_SUB_ID));
                long temp = jsonObject.getLong(BusinessConstant.PRODUCT_SUB_ID);
//                ContractProductEntity contractProductModelByKey = contractProductModel.getByKey(temp, corpid);
                ContractProductEntity entity = orginProductMapCopy.get(temp);
                if(entity!=null){
                    Long refProductId = entity.getRefProductId();
                    changeNumMap.put(refProductId, Arith.sub(productNum, originNum));
                }
            }
            if(jsonObject.get(BusinessConstant.REF_PRODUCT_ID)!=null){
                long refProductId = jsonObject.getLong(BusinessConstant.REF_PRODUCT_ID);
                if(!changeNumMap.containsKey(refProductId)){
                    contractProductEntity.setRefProductId(refProductId);
                    changeNumMap.put(refProductId, Arith.sub(productNum, originNum));
                }
            }
        }

        if(!productUpdateList.isEmpty()){
            for (ContractProductEntity updateProduct : productUpdateList) {
                JSONObject jsonObject = updateProduct.getData();
                if (Objects.nonNull(jsonObject)){
                    jsonObject.remove(ProductConstant.SEQ);
                    jsonObject.remove(ProductEnum.ENABLE_SERIAL_NUMBER.getSaasAttr());
                    jsonObject.remove(ProductEnum.ENABLE_BATCH_SHELF_LIFE.getSaasAttr());
                }
                contractProductModel.update(updateProduct);
            }
        }
        if(!orginProductMap.isEmpty()){
            for (Map.Entry<Long, ContractProductEntity> entry : orginProductMap.entrySet()) {
                ContractProductEntity delProduct = entry.getValue();
                changeNumMap.put(delProduct.getRefProductId(), Arith.sub(0D, Math.abs(delProduct.getProductNum())));
                // 删除产品时，更新序列号结存记录，删除序列号流水记录
                updateSerial(delProduct);
                contractProductModel.deleteByKey(delProduct.getId(), delProduct.getCorpid());
            }
        }
        if(!productAddList.isEmpty()){
            for (ContractProductEntity addProduct : productAddList) {
                JSONObject productData = addProduct.getData();
                JSONArray seqArray = productData.getJSONArray(ProductConstant.SEQ);
                int enableSerialNumber = productData.getIntValue(ProductEnum.ENABLE_SERIAL_NUMBER.getSaasAttr());
                // 移除序列号相关数据，不存入关联产品数据中
                productData.remove(ProductConstant.SEQ);
                productData.remove(ProductEnum.ENABLE_SERIAL_NUMBER.getSaasAttr());
                productData.remove(ProductEnum.ENABLE_BATCH_SHELF_LIFE.getSaasAttr());

                contractProductModel.insert(addProduct);
                // 新增序列号，关联产品不保存序列号，但是后面序列号保存以及生成出入库单需要序列号数据，所以给他加回去
                if (Objects.nonNull(seqArray) && !seqArray.isEmpty()) {
                    productData.put(ProductConstant.SEQ, seqArray);
                    productData.put(ProductEnum.ENABLE_SERIAL_NUMBER.getSaasAttr(), enableSerialNumber);
                }
                JSONArray jsonArray = new JSONArray();
                jsonArray.add(productData);
                saveSerial(newRefundEntityExt, jsonArray);
            }
        }
        return changeNumMap;
    }


    private void updateSerial(ContractProductEntity delProduct) throws XbbException {
        productSerialFlowModel.delByRefProductAndBusinessType(delProduct.getCorpid(), delProduct.getId(), XbbRefTypeEnum.REFUND.getCode());

        List<ProductSerialBalanceEntity> balanceEntities = productSerialBalanceModel.getByRefProductId(delProduct.getId(), XbbRefTypeEnum.REFUND.getCode(), delProduct.getCorpid());
        if (Objects.nonNull(balanceEntities)) {
            for (ProductSerialBalanceEntity entity : balanceEntities) {
                String seqKey = entity.getSeqKey();

                ProductSerialFlowEntity lastSerialFlow = productSerialFlowModel.getLastSerialFlow(delProduct.getCorpid(), seqKey, entity.getRefId());
                entity.setRefId(lastSerialFlow.getRefId());
                entity.setBusinessType(lastSerialFlow.getBusinessType());
                entity.setRefProductId(lastSerialFlow.getRefProductId());
                entity.setAddTime(lastSerialFlow.getAddTime());
                entity.setUpdateTime(lastSerialFlow.getUpdateTime());
                entity.setDate(lastSerialFlow.getDate());
                entity.setWarehouseId(lastSerialFlow.getWarehouseId());
                productSerialBalanceModel.update(entity);
            }
        }
    }

    public List<Long> generateRedPaymentPlan(ContractEntityExt redContractEntity, JSONArray paymentArray, SaasFormSaveDTO saasFormSaveDTO) throws XbbException {
        List<Long> redPaymentIds = new ArrayList<>();
        JSONObject newData = saasFormSaveDTO.getNewData();
        if (redContractEntity == null || newData == null) {
            return redPaymentIds;
        }
        if (paymentArray == null || paymentArray.isEmpty()) {
            return redPaymentIds;
        }
        // 退货退款关联的应收款
        for(Object obj : paymentArray) {
            JSONObject paymentJsonObject = (JSONObject) obj;
            String refundCreatorId = saasFormSaveDTO.getNewPaasFormDataEntity().getCreatorId();
            if (refundCreatorId != null) {
                paymentJsonObject.put(StringConstant.CREATOR_ID, refundCreatorId);
            }
            PaasFormDataEntityExt paymentEntityExt = handlePaymentSheetWebPlatformLinkAddData(paymentJsonObject);
            FormDataAddDTO formDataAddDTO = new FormDataAddDTO();
            BeanUtil.copyProperties(paymentEntityExt, formDataAddDTO);
            BeanUtil.copyProperties(saasFormSaveDTO, formDataAddDTO);
            JSONObject dataList = paymentEntityExt.getData();
            formDataAddDTO.setBusinessType(XbbRefTypeEnum.PAYMENT.getCode());
            formDataAddDTO.setSubBusinessType(XbbRefTypeEnum.PAYMENT.getCode());
            formDataAddDTO.setDataList(dataList);
            formDataAddDTO.setSaasMark(SaasMarkEnum.SAAS.getCode());
            SaasNeedRedundantAttrPojo saasNeedRedundantAttrPojo = new SaasNeedRedundantAttrPojo();
            saasNeedRedundantAttrPojo.setRefundId(saasFormSaveDTO.getNewPaasFormDataEntity().getId());
            formDataAddDTO.setSaasNeedRedundantAttrPoJo(saasNeedRedundantAttrPojo);
            JSONArray ownerJsonArray = paymentJsonObject.getJSONArray(FieldTypeEnum.OWNERID.getAlias());
            JSONArray coUserJsonArray = paymentJsonObject.getJSONArray(FieldTypeEnum.COUSERID.getAlias());
            List<ReturnUserAndDepartmentPojo> ownerId = new ArrayList<>();
            List<ReturnUserAndDepartmentPojo> coUserId = new ArrayList<>();
            if (Objects.nonNull(ownerJsonArray) && ownerJsonArray.size() > BasicConstant.ZERO) {
                ownerId = JSONArray.parseArray(ownerJsonArray.toJSONString(), ReturnUserAndDepartmentPojo.class);
            }
            if (Objects.nonNull(coUserJsonArray) && coUserJsonArray.size() > BasicConstant.ZERO) {
                coUserId = JSONArray.parseArray(coUserJsonArray.toJSONString(), ReturnUserAndDepartmentPojo.class);
            }
            formDataAddDTO.setOwnerId(ownerId);
            formDataAddDTO.setCoUserId(coUserId);
            formDataAddDTO.setPlatform(PlatFormEnum.INTERNAL.getValue());
            //工作流审批通过的时候生成红冲应收款的时候，dataId应该要为空，不然生成的红冲应收款是没有团队的
            // formDataAddDTO.setDataId(null); // 字段已被删除
            FormDataAddVO formDataAddVO = workflowOperatorDataService.add(formDataAddDTO);
            if (formDataAddVO.getDataId() != null) {
                redPaymentIds.add(formDataAddVO.getDataId());
            }
        }
        return redPaymentIds;
    }
}
